/**
 * @author:cavion(曹仁道)
 * @email:caorendao187@163.com
 * 2018年2月6日
 */
package org.rk.core.nosql.mongodb.base;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rk.core.nosql.mongodb.util.MongoFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;

/**
 * @author cavion
 * @描述
 * 2018年2月6日 下午1:06:43
 */
public class BaseMongoDao<T> implements IBaseMongoDao<T> {

	private Class<T> clazz;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoFactory mongoFactory;
    
    @SuppressWarnings("unchecked")
	public BaseMongoDao() {
        ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
        clazz = (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }
	@Override
	public T findOne(String id) {
		Query query = new Query();
        query.addCriteria(new Criteria("_id").is(id));
        return getMongoTemplate().findOne(query,clazz);
	}

	@Override
	public List<T> find(Query query) {
		return getMongoTemplate().find(query,clazz);
	}

	@Override
	public Long findCount(Query query) {
		return getMongoTemplate().count(query,clazz);
	}

	@Override
	public List<T> findListOrderByCreateTime(Integer skip, Integer limit, Query query) {
        List<String> orderFieldList = new ArrayList<String>();
        orderFieldList.add("createTime");
        return findListByOrder(skip, limit, query, orderFieldList);
	}
	@Override
	public List<T> findListByOrder(Integer skip, Integer limit, Query query,List<String> orderFieldList) {
        Map<Direction,String> orderFieldMap = new HashMap<Direction,String>();
        for (String fieldStr : orderFieldList) {
        	orderFieldMap.put(Direction.ASC, fieldStr);
		}
        return findListByOrder(skip, limit, query, orderFieldMap);
	}
	@SuppressWarnings("deprecation")
	@Override
	public List<T> findListByOrder(Integer skip, Integer limit, Query query,Map<Direction,String> orderFieldMap) {
		List<Order> orders = new ArrayList<>();
		for (Direction key : orderFieldMap.keySet()) {
			Order order = new Order(key, orderFieldMap.get(key));
			orders.add(order);
		}
		query.with(new Sort(orders));
        query.skip(skip).limit(limit);
        return find(query);
	}

	@Override
	public void insert(T entity) {
		mongoTemplate.insert(entity);
	}

	@Override
	public List<JSONObject> execQueryCmd(Query query,String collectionName) {
		List<JSONObject> jsonList = getMongoTemplate().find(query,JSONObject.class,collectionName);
		return jsonList;
	}
	
	@Override
	public Long update(Query query, Update update) throws Exception {
		UpdateResult updateResult = getMongoTemplate().updateFirst(query,update,clazz);
        return null == updateResult ? 0 : updateResult.getMatchedCount();
	}

	@Override
	public Long update(T entity) throws Exception {
		Map<String,Object> map = mongoFactory.converObjectToParams(entity);
        Query query = new Query();
        query.addCriteria(new Criteria("_id").is(map.get("id")));
        Update update = (Update) map.get("update");
        return this.update(query,update);
	}

	@Override
	public Long remove(T entity) {
		DeleteResult deleteResult = getMongoTemplate().remove(entity);
        return (null == deleteResult ? 0 : deleteResult.getDeletedCount());
	}

	@Override
	public Long remove(Query query, T entity) {
		DeleteResult deleteResult = getMongoTemplate().remove(query,entity.getClass());
        return (null == deleteResult ? 0 : deleteResult.getDeletedCount());
	}
	public MongoTemplate getMongoTemplate(){
        return mongoTemplate;
    }
}
